/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package mathma.core.value;

import mathma.core.real.Real;
import mathma.core.real.FiniteReal;
import mathma.core.expr.Variable;
import mathma.core.expr.Expression;

import mathma.core.simp.ComplexSimplifier;

/**
 * @since 0.2.1
 * @author Ethan Levine
 */
public class Complex extends Value<Complex> {

    public final static ValueType<Complex> Type =
            new ValueType<Complex>(ComplexSimplifier.Simplifier,
            Complex.class);

    private final Real realPart;
    private final Real imaginaryPart;

    public Complex(Real realPart, Real imaginaryPart) {
        super(Type);
        this.realPart = realPart;
        this.imaginaryPart = imaginaryPart;
    }

    @Override
    public Expression<Complex> differentiate(Variable<Complex> var) {
        return new Complex(Real.ZERO, Real.ZERO);
    }

    public Real real() {
        return realPart;
    }

    public Real imaginary() {
        return imaginaryPart;
    }

    public Complex add(Complex operand) {
        return new Complex(real().add(operand.real()),
                imaginary().add(operand.imaginary()));
    }

    public Complex subtract(Complex operand) {
        return new Complex(real().subtract(operand.real()),
                imaginary().subtract(operand.imaginary()));
    }

    public Complex multiply(Complex operand) {
        return new Complex(real().multiply(operand.real()).
                subtract(imaginary().multiply(operand.imaginary())),
                real().multiply(operand.imaginary()).add(imaginary().
                multiply(operand.real())));
    }

    public Complex divideBy(Complex operand) {
        Real denom = operand.real().multiply(operand.real()).add(
                operand.imaginary().multiply(operand.imaginary()));
        return new Complex(real().multiply(operand.real()).add(imaginary().
                multiply(operand.imaginary())).divideBy(denom),
                imaginary().multiply(operand.real()).subtract(real().multiply(
                operand.imaginary())).divideBy(denom));
    }

    public Real absoluteValue() {
        return real().multiply(real()).add(imaginary().multiply(imaginary())).sqrt();
    }

    public Complex conjugate() {
        return new Complex(real(), imaginary().negate());
    }

    public Complex reciprocal() {
        // Uses faster method than divideBy.
        Real abs = absoluteValue();
        Complex conj = conjugate();
        return new Complex(conj.real().divideBy(abs), conj.imaginary().divideBy(abs));
    }
}
